#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <assert.h>
#include <unordered_map>
#include <functional>
#include "sock.hpp"
#include "Epoll.hpp"
#include "Protocol.hpp"

using namespace std;

class Connection;
class TcpServer;

using func_t = std::function<void(Connection *)>;
using callback_t = function<void(Connection *, string &request)>;
// 我们为了能够正常工作，常规的sock必须是要有自己独立的接收缓冲区&&发送缓冲区
class Connection
{
public:
    Connection(int sock = -1)
        : _sock(sock), _tsvr(nullptr)
    {
    }

    void SetCallBack(func_t recv_cb, func_t send_cb, func_t execpt_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _execpt_cb = execpt_cb;
    }

    ~Connection()
    {
    }

public:
    // 负责IO的文件描述符
    int _sock;
    // 三个回调方法，_sock对应的方法
    func_t _recv_cb;
    func_t _send_cb;
    func_t _execpt_cb;
    // 发送、接受缓冲区
    string _in_buff;
    string _out_buff;
    // 设置TcpServer的回值指针
    TcpServer *_tsvr;

    // 关闭长时间不连接的sock
    uint64_t _lastTimeMap;
};

//

class TcpServer
{
    static const int g_num = 128;

public:
    TcpServer(int port = 8080)
        : _port(port), _revs_num(g_num)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        // 添加多路转接
        _poll.CreateEpoll();

        // 添加listensock到服务器中    //bind ???留疑问
        AddConnection(_listensock, bind(&TcpServer::Accepter, this, placeholders::_1), nullptr, nullptr);

        // 构建就绪事件缓冲区
        _revs = new struct epoll_event[_revs_num];
    }

    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t execpt_cb)
    {

        Sock::SetNonBlock(sock); // 设置非阻塞
        // 每个sock都会被封装成Connection，TcpServer对Connection进行管理

        // 构建Connection对象，封装sock
        Connection *con = new Connection(sock);
        con->SetCallBack(recv_cb, send_cb, execpt_cb);
        con->_tsvr = this;
        con->_lastTimeMap = time(nullptr);
        // 将sock添加到epoll中
        // 1)将sock添加到epoll中
        _poll.AddSockToEpoll(sock, EPOLLIN | EPOLLET); // 一般多路转接只打开读事件关心，处理方式设置为ET

        // 2)将对应的Connection*添加到Connection映射表中
        _connections.insert(make_pair(sock, con));
    }

    void Accepter(Connection *con)
    {
        // 处理业务区域
        // logMessage(DEBUG, "Accept calls...");
        while (true)
        {
            // 此处的sock一定就绪了
            string clientip;
            uint16_t clientport;
            int accept_error = 0;
            // sock一定是常规的IO
            int sock = Sock::Accpet(con->_sock, &clientip, &clientport, &accept_error);
            if (sock < 0)
            {
                if (accept_error == EAGAIN || accept_error == EWOULDBLOCK)
                    break; // 底层无连接了
                else if (accept_error == EINTR)
                    continue; // IO时被中断了
                else
                { // 真失败了
                    logMessage(WARNING, "accept error,%d: %s",
                               accept_error, strerror(accept_error));
                    break;
                }
            }
            else
            // if (sock >= 0)
            {
                // 将sock交给TcpServer   //    绑定的方法 ，绑定的对象，参数
                AddConnection(sock, bind(&TcpServer::Recver, this, placeholders::_1),
                              bind(&TcpServer::Sender, this, placeholders::_1),
                              bind(&TcpServer::Excepter, this, placeholders::_1));
                logMessage(DEBUG, "accept client %s: %d success,and add epoll and Tcpserver,sock: %d",
                           clientip.c_str(), clientport, sock);
            }
        }
    }

    void EnableReadWrite(Connection *con, bool readable, bool writeable)
    {
        uint32_t event = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0);
        bool res = _poll.CtrlEpoll(con->_sock, event);
        assert(res);
    }

    void Recver(Connection *con)
    {
        con->_lastTimeMap = time(nullptr);

        const int num = 1024;
        bool err = false;
        // logMessage(DEBUG, "Recver event exists,Recver is called");
        // version 1：直接面向字节流
        while (true)
        {
            char buff[num];
            ssize_t n = recv(con->_sock, buff, sizeof(buff) - 1, 0);
            if (n < 0)
            {
                if (errno == EAGAIN || n == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    logMessage(ERROR, "recv error, %d: %s", errno, strerror(errno));
                    con->_execpt_cb(con);
                    err = true;
                    break;
                }
            }
            else if (n == 0) // 对端关闭连接
            {
                logMessage(DEBUG, "client[%d] quit,server close [%d]",
                           con->_sock, con->_sock);
                con->_execpt_cb(con);
                err = true;
                break;
            }
            else
            {
                // 读成功
                buff[n] = 0;
                con->_in_buff += buff;
            }
        }
        logMessage(DEBUG, "con->_inbuff[ sock:%d ]: %s", con->_sock, con->_in_buff.c_str());
        if (!err)
        {
            vector<string> message;
            SplitMessage(con->_in_buff, &message);
            for (auto &msg : message)
            {
                // 这里一定是完整的报文
                _cb(con, msg); // 上层的处理方式
            }
        }
    }

    void Sender(Connection *con)
    {
        while (true)
        {
            ssize_t n = send(con->_sock, con->_out_buff.c_str(),
                             con->_out_buff.size(), 0);
            if (n > 0)
            {
                con->_out_buff.erase(0, n);
                if (con->_out_buff.empty())
                    break;
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                        break;
                    else if (errno == EINTR)
                        continue;
                    else
                    {
                        logMessage(ERROR, "send error, %d: %s", errno, strerror(errno));
                        con->_execpt_cb(con);
                        break;
                    }
                }
            }
            // 数据不一定发完了
            // 但能保证1、发完了  2、发送条件不满足，下次够了再发
        }
        if (con->_out_buff.empty())
            EnableReadWrite(con, true, false);
        else // 可以不写，写一开始就是打开的
            EnableReadWrite(con, true, true);
    }

    void Excepter(Connection *con)
    {
        if (!IsConnectionExiist(con->_sock))
            return;
        DeleLink(con);

        logMessage(DEBUG, "Except 回收完毕");
    }

    void DeleLink(Connection *con)
    {
        // 从epoll中移除
        if (!_poll.DelEpoll(con->_sock))
            exit(7); // 移除失败退出
        // 从unordered_map中移除
        _connections.erase(con->_sock);
        // close sock
        close(con->_sock);
        // delete con
        delete con;
    }

    bool IsConnectionExiist(int sock)
    {
        auto iter = _connections.find(sock);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }

    void LoopOnce()
    {
        int n = _poll.WaitEpoll(_revs, _revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            // 统一异常处理，防止下面的if报错
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN) // 读就绪s
            {
                if (IsConnectionExiist(sock) && _connections[sock]->_recv_cb) // 存在
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if (revents & EPOLLOUT) // 写就绪
            {
                if (IsConnectionExiist(sock) && _connections[sock]->_send_cb)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }

    void ConnectAliveCheck()
    {
        // 遍历所有的connections，检查活动时间，清除长时间无活动连接
        for (auto &iter : _connections)
        {
            uint64_t curtime = time(nullptr);
            uint64_t deadtime = curtime - iter.second->_lastTimeMap;
            if (deadtime > 300000)
            {
                // 关闭清除连接
                DeleLink(iter.second);
            }
        }
    }

    void Dispatcher(callback_t cb) // 根据就绪的事件，进行特定事件的派发
    {
        _cb = cb;
        while (true)
        {
            ConnectAliveCheck();
            LoopOnce();
        }
    }

    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_revs)
            delete[] _revs;
    }

private:
    int _listensock;
    int _port;
    Epoll _poll;
    // sock映射到自己的connection
    unordered_map<int, Connection *> _connections;
    struct epoll_event *_revs;
    int _revs_num;

    // 上层业务处理
    callback_t _cb;
};
